/* ===================================
Michal Kowalczyk
2010 EZI
==================================== */

#pragma once
// engine.h - basic systems, structures and interfaces for application
//
// class STLogger - error logging system, singleton.
// struct Settings - load from config.txt file
// class IEntity - the interface for entites.
// class IView - the interface for views.
// class Process - base class for all processes. 
// class ProcessManager - singleton.
// class EntityManager - the manager of all objects that exist as a part of program logic, singleton.
// class Core - main core based on SDL, handling input and loading configuration from a file.
//

class STLogger {
private:
	static STLogger* _instance;
	int m_lvl;							// 0 - NOTHING; 1 - ERRORS ONLY; 2 - EVERYTHING
	std::string m_filename;
protected:
	STLogger();
	~STLogger() {};
	STLogger(const STLogger &);             
	STLogger & operator=(const STLogger &);
public:
	static STLogger & Instance();
	void setLevel(const int & lvl) 
	{
		m_lvl = lvl; 
	}
	bool setup(std::string filename, const int & lvl, std::string appname, std::string appver);
	void log(std::string msg, const int & isError);
	void log(std::string msg, const int & value, const int & isError);
};
struct CollisionInfo
{
	bool collision;
	int withWhat;
	CollisionInfo(): collision(false), withWhat(0) {};
};
struct Position3D {
	float x, y, z, angle, rotx, roty, rotz;
	Position3D(): x(0), y(0), z(0), angle(0), rotx(0), roty(0), rotz(0) {};
	Position3D(const float & xx, const float & yy, const float & zz): x(xx), y(yy), z(zz), \
		angle(0.0f), rotx(0.0f), roty(0.0f), rotz(0.0f) {};
	Position3D(const Position3D & vec) 
	{ 
		x = vec.x; y = vec.y; z = vec.z;
		angle = vec.angle; rotx = vec.rotx; roty = vec.roty; rotz = vec.rotz;
	}
};
typedef boost::shared_ptr<Position3D> PositionPtr;

typedef int EntityID;

class IEntity 
{
public:
	virtual ~IEntity() {};
	virtual int getId() = 0;
	virtual Position3D getPosition3D() = 0;
	virtual void setPosition3D(float x, float y, float z) = 0;
	virtual void setPosition3D(float x, float z) = 0;
	virtual void setHeight(float y) = 0;
	virtual void setPosition3D(float & x, float & y, float & z, float & angle, float & rotx, float & roty, float & rotz) = 0;
	virtual void setPosition3D(float & angle, float rotx, float roty, float rotz) = 0; 
	virtual std::string getType() = 0;
	virtual void update() = 0;

	virtual void setRegion(int r) = 0;
	virtual int getRegion() = 0;
};

class IView
{
public:
	virtual ~IView() {};
	virtual std::string getType() = 0;
	virtual void update() = 0;
	virtual void render() = 0;
};

typedef boost::shared_ptr<IEntity> EntityPtr;
typedef boost::shared_ptr<IView> ViewPtr;

struct Settings
{
	int screen_width;
	int screen_height;
	int full_screen;
	int log_level;
	std::string media_path;
	int fps;
	float cameraSpeed;
	float mouseSpeed;
	int blending;
	int fog;
	float fogstart;
	float fogend;
	float fov;
	float nearcl;
	float farcl;
	int text_output;
	int video_output;
	Settings(): screen_width(800), screen_height(600), full_screen(0), log_level(2), \
		media_path("../../media"), fps(60), cameraSpeed(0.1f), blending(0), fog(1), fogstart(10.0f), \
		fogend(50.0f), fov(45.0f), nearcl(1.0f), farcl(60.0f), text_output(0), \
		video_output(1) {};
};


// =====================================================
// ENTITY MANAGER
// =====================================================

// maps data models by ID
typedef std::map< EntityID, boost::shared_ptr<IEntity> > EntityMap;

// maps corresponding views by ID
typedef std::map< EntityID, boost::shared_ptr<IView> > ViewMap;

class EntityManager {
private:
	static EntityManager* _instance;
	int size;
	EntityManager(): size(0) {};
	~EntityManager() {};
	EntityManager(const EntityManager &);             
	EntityManager & operator=(const EntityManager &); 

	EntityMap m_entityMap;

public:
	static EntityManager & Instance();

	// TODO
	bool init() 
	{ 
		return true; 
	}
	bool addEntity(EntityID id, EntityPtr entity);
	EntityPtr getEntity(EntityID id)
	{
		return m_entityMap[id];
	}
	int getSize()
	{
		return size;
	}


};


// =====================================================
// PROCESS MANAGER
// =====================================================

class Process;
typedef boost::shared_ptr<Process> ProcessPtr;
typedef std::list< boost::shared_ptr<Process> > ProcessList;

class Process 
{
private:
	friend class ProcessManager;
protected:
	bool m_active;
	bool isDead;
	ProcessPtr m_next;
	EntityManager & entityManager;
public:
	Process(): isDead(false), m_active(true), entityManager(EntityManager::Instance()), \
		m_next(ProcessPtr((Process *)NULL)) {};
	virtual void update() = 0;
	//virtual void kill() = 0;
	void setNext(ProcessPtr process) 
	{ 
		m_next = process;
	}
	ProcessPtr getNext()
	{ 
		return m_next;
	}
};

// TODO
class ProcessManager 
{
private:
	static ProcessManager* _instance;
	ProcessManager() {};
	~ProcessManager() {};
	ProcessList m_processList;
	bool detach(ProcessPtr process);
	ProcessList::iterator i;
	ProcessList::iterator end;
public:
	static ProcessManager & Instance();
	bool attach(ProcessPtr process);
	void updateProcesses();
};

// CORE
class Core
{
private:

	const std::string app_name;
	const std::string app_ver;

	static const std::string m_configfile;
protected:
	STLogger & logger;
	static Settings settings;

	bool keys[512];
	static bool running;

public:

	// the SDL stuff for handling input
	virtual void handleKeyDown(SDL_keysym* keysym);
	virtual void handleKeyUp(SDL_keysym* keysym);
	void handleSDLEvents();
	static void handleConsoleEvents();
	bool loadSettings(std::string configfile);
	static Settings & getSettings() { return settings; };

	bool SDLinit();
	void waitFrame(int fps);

	// function to override
	virtual void run() = 0;

	Core(std::string appname, std::string appver);
	virtual ~Core() {};
};

